package cn.shanguoyu.base.springboot.starter.limit.autoconfig;

import cn.shanguoyu.base.springboot.starter.cache.abs.Cache;
import cn.shanguoyu.base.springboot.starter.cache.autoconfig.CacheAutoConfiguration;
import cn.shanguoyu.base.springboot.starter.limit.aop.LimitAspect;
import cn.shanguoyu.base.springboot.starter.limit.manager.abs.LimiterManager;
import cn.shanguoyu.base.springboot.starter.limit.manager.impl.GuavaLimiter;
import cn.shanguoyu.base.springboot.starter.limit.manager.impl.RedisLimiter;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;

/**
 * @description:自动配置
 * @author：sgy
 * @date: 2023-06-01
 */
@Configuration
public class LimitAutoConfiguration {
    private static final String LUA_LIMIT_SCRIPT_PATH = "lua/limit.lua";

    /**
     * 限流器
     *
     * @return
     */
    @Bean
    @ConditionalOnProperty(name = "base.limit.type", havingValue = "local", matchIfMissing = true)
    public LimiterManager guavaLimiter() {
        return new GuavaLimiter();
    }

    /**
     * 限流器
     *
     * @param
     * @return
     */
    @Bean
    @ConditionalOnProperty(name = "base.limit.type", havingValue = "distributed")
    @ConditionalOnClass(value = Cache.class)
    public LimiterManager redisLimiter(Cache cache) {
        return new RedisLimiter(cache, limitScript());
    }

    /**
     * 限流切面
     *
     * @param limiterManager
     * @return
     */
    @Bean
    public LimitAspect limitAspect(LimiterManager limiterManager) {
        return new LimitAspect(limiterManager);
    }

    /**
     * 分布式限流的Lua脚本
     *
     * @return
     */
    @Bean
    public DefaultRedisScript<Long> limitScript() {
        DefaultRedisScript<Long> defaultRedisScript = new DefaultRedisScript<>();
        defaultRedisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource(LUA_LIMIT_SCRIPT_PATH)));
        defaultRedisScript.setResultType(Long.class);
        return defaultRedisScript;
    }
}
